<html>
<head>
<title>TurKit Editor</title>
<link rel="stylesheet" href="jquery.contextMenu.css" />
<style type="text/css">
table,caption,tbody,tfoot,thead,tr,th,td {
	margin: 0;
	padding: 0;
	border: 0;
	outline: 0;
	font-size: 100%;
	vertical-align: baseline;
	background: transparent;
}

img {
	border-style: none;
}

table {
	border-collapse: collapse;
}

.clear {
	overflow: hidden;
	width: 100%;
}

body {
	font-family: sans-serif;
}

.user {
	float: right;
	text-align: right;
}

.keys {
	float: left;
	margin-right: 20px;
}

.keys input {
	border: 1px solid rgb(233, 233, 233);
}

iframe.editor {
	width: 100%;
	height: 100%;
	border: 1px solid rgb(233, 233, 233);
}

.buttonLink {
	font-size: small;
	cursor: pointer;
	color: blue;
	text-decoration: none;
}

a.buttonLink:hover {
	text-decoration: underline;
}

.open.project {
	margin-top: 10px;
	margin-bottom: 10px;
	background: #f0f0ff;
}

.title {
	overflow: hidden;
	width: 100%;
	cursor: pointer;
}

.title>.buttonLink {
	font-size: medium;
	color: black;
}

.closeButtons {
	float: right;
}

.open.project>.title {
	background: #a0a0ff;
}

.open.project>.title>.buttonLink {
	font-weight: bold;
}

.open.file>.title>.buttonLink {
	font-weight: bold;
}

.project .files {
	margin-left: 20px;
}

.project .files .file {
	
}

.title>.control {
	float: right;
	margin-right: 3px;
}

.iconButton {
	cursor: pointer;
	width: 16px;
	height: 16px;
}

.hide {
	visibility: hidden;
}

div.title:hover .hide {
	visibility: visible;
}

.runButton {
	background-image: url('icons/run_grey.png');
}

div.runButton:hover {
	background-image: url('icons/run.png');
}

.rerunButton {
	width: 24px;
	background-image: url('icons/rerun_grey.png');
}

div.rerunButton:hover,div.rerunButton.buttonOn {
	background-image: url('icons/rerun.png');
}

.stopButton {
	background-image: url('icons/stop_grey.png');
}

div.stopButton:hover,div.stopButton.buttonOn {
	background-image: url('icons/stop.png');
}

.sandboxModeButton {
	background-image: url('icons/sandbox_grey.png');
}

div.sandboxModeButton:hover,div.sandboxModeButton.buttonOn {
	background-image: url('icons/sandbox.png');
}

.realModeButton {
	background-image: url('icons/real_grey.png');
}

div.realModeButton:hover,div.realModeButton.buttonOn {
	background-image: url('icons/real.png');
}

.ui-layout-pane {
	padding: 10px;
}

.ui-layout-resizer {
	background: #EEE;
}

.ui-layout-pane.ui-layout-east {
	padding: 0px;
}

.ui-layout-pane.ui-layout-west {
	padding: 0px;
}

</style>
</head>
<body>
<script src="jquery.js"></script>
<script src="jquery.ui.js"></script>
<script src="jquery.layout.js"></script>
<script src="jquery.contextMenu.js"></script>
<script src="tab.js"> </script>
<script src="myutil.js"></script>
<script>

___COMMON___

var openProjectKey = null
var openFileKey = null

$(function () {
	var ie = {"currently does not support IE.":true,}
	$('#ie').remove()

	$('body').layout({
        //applyDefaultStyles: true,
        closable: false,
        east__size: 300,
        west__size: 200
    })
	$('div.ui-layout-east').layout({
        //applyDefaultStyles: true,
        center__paneSelector: ".east-center",
        south__paneSelector: ".east-south",
        closable: false,
        south__size: 200
    })
	$('div.ui-layout-west').layout({
        //applyDefaultStyles: true,
        center__paneSelector: ".west-center",
        south__paneSelector: ".west-south",
        closable: false,
        south__size: 200
    })
	
	$('#center').css('overflow', 'hidden')
	$('#east, #eastSouth').css('overflow', 'hidden')
	
	$('#newProject').click(function () {
		createProject()
	})

	// set user	
	var user = ___USER___
	$('#username').text(user.name)
	$('#awsId').val(user.awsId)
	$('#awsKey').val(user.awsKey)
	registerSaveable($('#awsId, #awsKey'), function (cont) {
		ajaxCont('/api', {
				"method" : "setUser",
				"awsId" : $('#awsId').val(),
				"awsKey" : $('#awsKey').val()
			}, function (e) {}, cont)
	})
	
	// example projects
	ajaxCont('/api', {
		"method" : "getExampleProjects"		
	}, function (e) {
		foreach(eval(e), function (e) {
			$('#exampleProjects').append($('<div>' + escapeXml(e.replace(/-/g, ' ')) + 
				'<div class="buttonLink" style="float:right">clone</div></div>').click(function () {
					createProject(e)
				}))
		})
	})
	
	fetchAndUpdate()
})

function fetchAndUpdate() {
	getProjects(function (projs) {
		var openProject = null
		if (openProjectKey) {
			var a = filter(projs, function (proj) {return proj.key == openProjectKey})
			if (a.length > 0) {
				openProject = a[0]
			} else {
				openProjectKey = null
			}
		}
		if (!openProjectKey && projs.length > 0) {
			openProjectKey = projs[0].key
			openProject = projs[0]
		}
		if (openProjectKey) {
			getFiles(openProjectKey, function (files) {
				openProject.files = files
				var openFile = null
				if (openFileKey) {
					var a = filter(files, function (file) {return file.key == openFileKey})
					if (a.length > 0) {
						openFile = a[0]
					} else {
						openFileKey = null
					}
				}
				foreach(files, function (file) {
					if ((openFileKey && file.key == openFileKey) ||
						(!openFileKey && file.name == "main.js")) {
						openFileKey = file.key
						file.open = true
					}
				})
				updateEverything(projs)
			})
		} else {
			updateEverything(projs)
		}
	})
}

function getProjects(cont) {
	var projects = null
	ajaxCont('/api', {
			"method" : "getProjects"
		},
		function (e) {
			projects = eval(e)
		},
		function () {
			cont(projects)
		})
}

function getFiles(projKey, cont) {
	var files = null
	ajaxCont('/api', {
			"method" : "getFiles",
			"project" : projKey
		},
		function (e) {
			files = eval(e)
		},
		function () {
			cont(files)
		})
}

function join(funcs, cont) {
	if (funcs.length > 0) {
		var count = funcs.length
		foreach(funcs, function (func) {
			func(function () {
				count--
				if (count <= 0) {
					cont()
				}
			})
		})
	} else {
		cont()
	}
}

function serial(funcs) {
	if (funcs.length > 0) {
		funcs[0](function () {
			serial(funcs.slice(1))
		})
	}
}

function performAction(func) {
	serial([
		save,
		func,
		fetchAndUpdate
	])
}

function createProject(fromExample) {
	var name = prompt('What should we call the new project?', "")
	if (name != null && name.length > 0) {
		performAction(function (cont) {
			ajaxCont('/api', {
				"method" : "createProject",
				"name" : name,
				"fromExample" : fromExample
			}, function (e) {
				var proj = eval(e)
				openProjectKey = proj.key
			}, cont)
		})
	}
}

function cloneProject(proj) {
	var name = prompt('What should we call the cloned project?',
				proj.name + "_clone")
	if (name != null) {
		performAction(function (cont) {
			ajaxCont('/api', {
				"method" : "clone",
				"project" : proj.key,
				"name" : name
			}, function (e) {
				var proj = eval(e)
				openProjectKey = proj.key
			}, cont)
		})
	}
}

function deleteProject(proj) {
	if (confirm('Are you sure you want to delete the project "' + proj.name + '"?')) {
		performAction(function (cont) {
			ajaxCont('/api', {
				"method" : "delete",
				"project" : proj.key
			}, function (e) {}, cont)
		})
	}
}

function cloneFile(file) {
	var name = prompt('What should we call the cloned file?',
				file.name + "_clone")
	if (name != null) {
		performAction(function (cont) {
			ajaxCont('/api', {
				"method" : "clone",
				"file" : file.key,
				"name" : name
			}, function (e) {
				var file = eval(e)
				openFileKey = file.key
			}, cont)
		})
	}
}

function deleteFile(file) {
	if (confirm('Are you sure you want to delete the file "' + file.name + '"?')) {
		performAction(function (cont) {
			ajaxCont('/api', {
				"method" : "delete",
				"file" : file.key
			}, function (e) {}, cont)
		})
	}
}

function createFile(proj) {
	var name = prompt('Filename? (must be unique within this project)')
	if (name != null) {
		performAction(function (cont) {
			ajaxCont('/api', {
				"method" : "createFile",
				"project" : proj.key,
				"name" : name
			}, function (e) {}, cont, function (e) {
				if (e.match(/<pre>file already exists:/)) {
					alert('the following filename is already used: ' + name)
					return false
				}
			})
		})
	}
}

function run(proj, reset) {
	if (!reset || confirm('Are you sure you want to delete the follow?:\n- all HITs created from this script\n- all webpages created from this script\n- all execution trace data\n- all data in db')) {
		performAction(function (cont) {
			ajaxCont('/api', {
					"method" : "run",
					"project" : proj.key,
					"reset" : reset
				}, function (e) {				
				}, cont)
		})
	}
}

function rerun(proj) {
	performAction(function (cont) {
		ajaxCont('/api', {
				"method" : "rerun",
				"project" : proj.key
			}, function (e) {				
			}, cont)
	})
}

function stop(proj) {
	performAction(function (cont) {
		ajaxCont('/api', {
				"method" : "stop",
				"project" : proj.key
			}, function (e) {				
			}, cont)
	})
}

function getMode(contents) {
	if (contents.match(/\bmode\s*:\s*['"]real['"]/)) return "real"
	if (contents.match(/\bmode\s*:\s*['"]sandbox['"]/)) return "sandbox"
}

function setMode(file, mode) {
	var a = file.contents
	var b = a.replace(/\b(mode\s*:\s*['"])([^'"]*)(['"])/, "$1" + mode + "$3")
	if (b == a) {
		b = a.replace(/\b(props\s+=\s*\{)/, "$1\n\tmode : \"" + mode + "\",")
	}
	if (mode != getMode(b)) {
		alert("I failed to change the mode to \"" + mode +
			"\".\nYou may need to do this manually in the props file.")
	} else {
		performAction(function (cont) {
			ajaxCont('/api', {
					"method" : "setFileContents",
					"file" : file.key,
					"contents" : b
				}, function (e) {}, cont)
		})
	}
}

function updateEverything(projects) {
	var projectsDiv = $('#projects')
	projectsDiv.empty()
	foreach(projects, function (project) {
		var projectDiv = $('<div></div>')
		projectDiv.addClass("project")
		
		var a = $('<div class="title"><a class="buttonLink"></a></div>')
		$('a', a).text(project.name).click(function () {
			performAction(function (cont) {
				openProjectKey = project.key
				cont()
			})
		})
        a.contextMenu({
            menu : 'projectMenu'
        }, function (action) {
        	if (action == "clone") {
        		cloneProject(project)
        	} else if (action == "delete") {
        		deleteProject(project)
        	} else {
        		alert("command not implemented: " + action)
        	}
        })
		projectDiv.append(a)
		
		if (project.files) {
			// sort files in a weird way
			function mainFileNum(file) {
				if (file.name == "props") return 1
				if (file.name == "main.js") return 2
				if (file.name == "output") return 3
				if (file.name == "db") return 4
				return false
			}
			function isNot(f) {return function (e) {return !f(e)}}
			function comp(a, b) {return (b < a) - (a < b)}
			
			project.files = filter(project.files, mainFileNum).sort(
				function (a, b) {return mainFileNum(a) - mainFileNum(b)}).concat(
					filter(project.files, isNot(mainFileNum)).sort(
						function (a, b) {return comp(a.name, b.name)}))
			
			updateEditors(project.files)
		
			projectDiv.addClass("open")
			
			var filesDiv = $('<div class="files"></div>')
			
			foreach(project.files, function (file, i) {
				var fileDiv = $('<div class="file"></div>')
				if (file.open) {
					fileDiv.addClass("open")
				}
				
				var a = $('<div class="title"><a class="buttonLink"></a></div>')
				$('a', a).text(file.name).click(function () {
					performAction(function (cont) {
						openFileKey = file.key
						cont()
					})
				})
				if (file.name == "main.js") {
					if (project.rerun) {
						a.append($('<div title="let it rerun automatically" class="control iconButton rerunButton buttonOn"></div>'))
					} else {
						a.append($('<div title="let it rerun automatically" class="control iconButton rerunButton"></div>').click(function () {
							rerun(project)
						}))
					}
					a.append($('<div title="run" class="control iconButton runButton"></div>').click(function () {
						run(project)
					}))
					if (project.rerun) {
						a.append($('<div title="stop" class="control iconButton stopButton"></div>').click(function () {
							stop(project)
						}))
					} else {
						a.append($('<div title="stop" class="control iconButton stopButton buttonOn"></div>'))
					}
				} else if (file.name == "db") {
					a.append($('<div title="reset database" class="control"></div>').append($('<a class="buttonLink">reset</a>').click(function () {
						run(project, true)
					})))
				} else if (file.name == "output") {
				} else if (file.name == "props") {
					var mode = getMode(file.contents)
					var sandbox = (mode == "sandbox")
					var real = (mode == "real")
					
					if (!real) {
						a.append($('<div title="use real money" class="control iconButton realModeButton"></div>').click(function () {
							setMode(file, "real")
						}))
					} else {
						a.append($('<div title="use real money" class="control iconButton realModeButton buttonOn"></div>'))
					}
					if (!sandbox) {
						a.append($('<div title="use sandbox" class="control iconButton sandboxModeButton"></div>').click(function () {
							setMode(file, "sandbox")
						}))
					} else {
						a.append($('<div title="use sandbox" class="control iconButton sandboxModeButton buttonOn"></div>'))
					}
				} else {
			        a.contextMenu({
			            menu : 'fileMenu'
			        }, function (action) {
			        	if (action == "clone") {
							cloneFile(file)
			        	} else if (action == "delete") {
							deleteFile(file)
			        	} else {
			        		alert("command not implemented: " + action)
			        	}
			        })
				}
				fileDiv.append(a)
				
				filesDiv.append(fileDiv)
				
				if (i == 3) {
					filesDiv.append($('<div style="margin-bottom:5px"></div>').append(
						$('<a class="buttonLink">new file</a>').click(function () {
							createFile(project)
						})))
				}
			})
			
			projectDiv.append(filesDiv)
		}
				
		projectsDiv.append(projectDiv)
	})
}

var prevEditors = {}

function updateEditors(files) {
	var editors = {}
	
	function getEditor(key, file, viewer) {
		if (viewer) {
			key += ":" + viewer
		}		
		var editor = prevEditors[key]
		                		
		var readonly = (file.name == "output") || (viewer == "traceView")
		                 		
		if (!editor) {
			var viewerParam = (viewer ? ("&" + viewer) : "")
			editor = $('<iframe class="editor" frameBorder="0" src="/editor?file=' + file.key + viewerParam + '&readonly=' + readonly + '&random=' + randomId(8) + '"></iframe>')
			editors[key] = editor
			return editor
		} else {
			editors[key] = editor
			if (readonly)
				editor.get(0).contentWindow.reload()
		}
	}
	
	function createTab(name, content, link) {
		var a = $('<table width="100%" height="100%"><tr><td>' + escapeXml(name) + (link ? link : '') + '</td></tr><tr height="100%"><td height="100%"><div a="content" style="width:100%;height:100%"></div></td></tr></table>')
		$('div[a=content]', a).append(content)
		return a
	}

	var file = filter(files, function (f) {return f.open})[0]
	var e = getEditor('center:' + file.key, file)
	if (e) {
		$('#center').empty().append(createTab(file.name, e))
	}

	if (file.name.match(/\.html$/)) {
		var e = getEditor('east:' + file.key, file, "reloadableView")
		if (e) {
			$('#east').empty().append(createTab(file.name, e))
		}
		var e = getEditor('east-south:' + file.key, file, "testDataEditor")
		if (e) {
			$('#eastSouth').empty().append(createTab(file.name, e))
		}
	} else {
		file = filter(files, function (f) {return f.name == "output"})[0]
		var e = getEditor('east:' + file.key, file)
		if (e) {
			$('#east').empty().append(createTab(file.name, e))
		}
		file = filter(files, function (f) {return f.name == "db"})[0]
		var e = getEditor('east-south:' + file.key, file, "traceView")
		if (e) {
			$('#eastSouth').empty().append(createTab("execution trace", e))
		}
	}
	
	prevEditors = editors
}

///////////////////////////////////////////////////////

var saveables = []

function registerSaveable(n, saveFunc) {
	var s = {
		node : n,
		timeout : 0,
		dirty : false,
		saving : 0			
	}
	saveables.push(s)
	
	s.save = function (cont) {
		clearTimeout(s.timeout)
		if (s.dirty) {
			s.dirty = false
			saveFunc(function () {
				cont()
			})
		} else {
			cont()
		}
	}
	
	s.oldValues = []
	s.updateOldValues = function () {
		foreach(n.get(), function (n) {
			s.oldValues.push($(n).val())
		})
	}
	s.updateOldValues()
	
	s.onChange = function() {
		var changed = false
		foreach(n.get(), function (n, i) {
			var v = $(n).val()
			if (v != s.oldValues[i]) {
				s.oldValues[i] = v
				changed = true
			}
		})
		if (!changed) return
	
		s.dirty = true
		clearTimeout(s.timeout)
		s.timeout = setTimeout(function () {
			s.save(function () {})
		}, 2000)
	}
	
	s.bind = function() {
		n.
			bind('keydown', s.onChange).
			bind('keyup', s.onChange).
			bind('keypress', s.onChange).
			bind('change', s.onChange)
	}
	
	s.unbind = function() {
		n.
			unbind('keydown', s.onChange).
			unbind('keyup', s.onChange).
			unbind('keypress', s.onChange).
			unbind('change', s.onChange)
	}
	
	s.remove = function() {
		s.save(function () {
			saveables = filter(saveables, function (e) {return e != s})
		})
	}
	
	s.bind()
	
	return s
}

function save(cont) {
	if ((typeof cont) != "function") cont = function () {}

	var editorSaves = map($('iframe.editor').get(), function (f) {
		var save = f.contentWindow.save
		if (save) return save
		return function (cont) {cont()}
	})
	
	var localSaves = map(saveables, function (e) {return e.save})
	
	join(editorSaves.concat(localSaves), cont)
}

</script>

<div id="ie"><b>NOTE: Internet Explorer is not yet supported by this site. (Firefox is supported.)</b></div>
<div id="north" class="ui-layout-north">
<div class="keys"><a href="/"><img style="margin-top:-6px;margin-left:-6px;margin-bottom:-10px" src="/logos/logo-140.png"></img></a></div>
<div class="keys"><a class="buttonLink" target="_blank"
	href="https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key">aws access
key id:</a> <br>
<input type="text" id="awsId" value=""></div>
<div class="keys"><a class="buttonLink" target="_blank"
	href="https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key">aws secret
access key:</a><br>
<input type="password" id="awsKey" value=""></input></div>
<div class="keys"><a class="buttonLink" href="/editor?warranty">beta - <b>use at your own risk</b></a><br>
</div>

<div class="user"><span id="username"></span><br>
<a class="buttonLink" href="___LOGOUT_URL___">logout</a></div>
</div>
<div class="ui-layout-west">
    <div id="west" class="west-center">
        <div style="margin-bottom: 5px"><a class="buttonLink" id="newProject">new project</a></div>
        <div id="projects"></div>
    </div>
    <div id="westSouth" class="west-south">
        <div><a class="buttonLink" target="_blank" href="/jsdocs/">API reference</a></div>
        <br>
        <div style="margin-bottom: 5px"><b><small>example projects</small></b></div>
        <div id="exampleProjects"></div>
    </div>
</div>
<div id="center" class="ui-layout-center"></div>
<div class="ui-layout-east">
    <div id="east" class="east-center"></div>
    <div id="eastSouth" class="east-south"></div>
</div>

<ul id="projectMenu" class="contextMenu">
    <li><a href="#clone">Clone</a></li>
    <li><a href="#delete">Delete</a></li>
</ul>

<ul id="fileMenu" class="contextMenu">
    <li><a href="#clone">Clone</a></li>
    <li><a href="#delete">Delete</a></li>
</ul>

</body>
</html>
